<?php
require_once($Config->WebCMSRoot.'Data/Page.php');
require_once($Config->WebCMSRoot.'Control.php');
require_once($Config->WebCMSRoot.'ErrorDocument.php');

// Classes that need to be declared before session_start() is called:
require_once($Config->WebCMSRoot.'Models/User.php');
require_once($Config->WebCMSRoot.'Models/Form.php');
require_once($Config->WebCMSRoot.'Models/Ticket.php');

ob_start();
session_start();
/*
TODO:
- fix in page cacheDuration setting:
  $this->pageConfig['cacheDuration'] = 30;
*/
class Page
{
	var $ID;
	var $file;          // php/xhtml file
	var $cacheCreated;  // timestamp
	var $cacheDuration; // seconds

	var $args;          // request arguments
	var $pageConfig;
	var $Config;
	var $User;
	var $Controls;
	var $IsDebug;
	var $IsTest;
	
	function Page($file)
	{
		$this->ID 				= 0;
		$this->file   			= '';
		$this->cacheDuration 	= 0; //60*60*24;
		$this->cacheCreated  	= mktime(0,0,0,1,1,2000);

		$this->args			= array();
		$this->pageConfig 	= array();
		$this->Config		= NULL;
		$this->User			= NULL;
		$this->Controls		= array();
		$this->IsDebug		= false;
		$this->IsTest		= false;
		
		global $Config;
		$this->Config = &$Config;
		if (isset($_SESSION['user']))
		{
			$this->User = unserialize(&$_SESSION['user']);
		}

		$this->pageConfig = array();
		$this->InitConfig();
		
//		$this->cacheCreated  	= mktime(date('H'), date('i'), -$this->cacheDuration - 1);

		$this->file = $file;
		
		if (preg_match('|_TEST[^_]*|', $this->file) == 1)
		{
			$this->IsTest = true;
			$this->file = preg_replace('|_TEST[^_]*|', '', $this->file);
		}
		
		if (preg_match('|_DEBUG[^_]*|', $this->file) == 1)
		{
			$this->IsDebug = true;
			$this->file = preg_replace('|_DEBUG[^_]*|', '', $this->file);
		}

//if ($this->IsDebug) {print('<pre>'.var_export($this, true).'</pre>');exit; }
		$db = new PageData();
		$db->Retrieve(&$this);
		
		if ($this->cacheDuration <> $this->pageConfig['cacheDuration'])
		{
			$this->cacheDuration = $this->pageConfig['cacheDuration'];
		}
	}
	
	function InitConfig()
	{
//if ($this->IsDebug) { print('<pre>'.var_export($this, true).'</pre>');exit; }
		$this->pageConfig['argCount'] = 1; // 1=page, override for / & /index.php
		$this->pageConfig['cacheDuration'] = $this->Config->CacheDuration;
	}
	
	function Persist()
	{
//if ($this->IsDebug) { print('<pre>'.var_export($this, true).'</pre>');exit; }
		$db = new PageData();

		$db->Update(&$this);
	}
	
	function IsCacheExpired()
	{
//print($this->cacheDuration);
		if (count($_POST) > 0)
		{
			return true;
		}
		
		if ($this->cacheDuration > 0)
		{
			$expired = $this->TimeAdd($this->cacheCreated, $this->cacheDuration);
//print($expired.' - '.mktime().' = '.($expired < mktime()));
			return ($expired < mktime());
		}

		return true;
	}
	
	function Generate($args, $staticPage=TRUE, &$dynamicFile)
	{
		$this->args = $args;
		$this->args[0] = strtolower($this->args[0]); // args[0] should always be the page in lower case

		$fileTemplate = $this->Config->SiteRoot.'pages/'.$this->args[0].'.php';
		if (!file_exists($fileTemplate)) // Allow override on site-level
		{
			$fileTemplate = $this->Config->WebCMSRoot.'Pages/'.$this->args[0].'.php';
			if (!file_exists($fileTemplate))
			{
				$this->Error404('Template file does not exist.');
			}
		}

//if ($this->IsDebug) { print('<pre>'.var_export($_SERVER, true).'</pre>');exit; }
		$uniqueID = md5(uniqid(rand(), true));
		$preprocessTemplate = 'http://' . $this->Config->Host . '/prefetch.php?p='.implode('|',$this->args) . '&prefetchID=' . $uniqueID . '&site=' . $this->Config->SiteID;
		$fileCache = $this->Config->SiteRoot.'cache/'.$this->file.'.php';
		$dynamicPage = $this->Config->SiteRoot.'cache/__temp__'.md5(uniqid($this->file)).'.php';

		$filePreCache = $this->Config->SiteRoot.'/prefetch/'.$uniqueID;
		$retval = false;

		// lees in & pre-process
		if (file_exists($fileTemplate))
		{
			// copy, prefetch and delete
			copy($fileTemplate, $filePreCache);
			$handle = fopen($preprocessTemplate, 'r');
			unlink($filePreCache);

			$template = '';
			do {
				$data = fread($handle, 8192);
				if (strlen($data) == 0) {
					break;
				}
				$template .= $data;
			} while(true);
			fclose($handle);

			// replace PHP code escapes
			$template = preg_replace ('|<!--\?php|', '<?php', $template);
			$template = preg_replace ('|\?-->|', '?>', $template);

			// replace arguments
			foreach ($this->args as $key=>$arg)
			{
				$template = preg_replace ('|\$\$'.$key.'\$\$|', $arg, $template);
			}
			
			// extract page configuration
			$pattern = '|(?:<!--ConfigurationSection<\?php)(?P<config>.*)(?:\?>/ConfigurationSection-->)|mis';
			$matches = preg_match_all($pattern, $template, $config, PREG_SET_ORDER);
			if (count($config) > 0)
			{
				eval($config[0]['config']);
			}

			$this->cacheDuration = $this->pageConfig['cacheDuration'];

			if ($this->IsValid())
			{
				// extract controls
				$pattern = '|(?P<control><WebCMS:(?:[^>]*)(?:(/>)))|mis';
				//$pattern = '|(?P<control><WebCMS:(?:[^/>]*)(?:[/>]*))|mis';
				$matches = preg_match_all($pattern, $template, $controls, PREG_SET_ORDER);
//if ($this->IsDebug) {print($matches);}

				$commands = array();
				foreach ($controls as $key=>$val)
				{
//if ($this->IsDebug) {print(htmlspecialchars($val['control']).'<br />');}
					// instantiate control
					$control = new Control($val['control'], $this->args, &$this);
					$this->Controls[] = $control;

					$commands[$key] = $control->output;
				}
                
// CONTROL INTERACTION COMES HERE
/*
1. every module 'raises' events: $raiseEvent[] = array('otherModuleName', 'eventName', $parameters);
    i.e. Blog: $this->raiseEvent[] = array('header', 'SetTitle', 'blogtitle');
2. every module 'catches' events
...
*/
/*
foreach ($this->Controls as $key=>$control)
{
    //print('<pre>'.var_export($control->module, true).'</pre>');
    print('<pre>'.var_export(get_class($control->module), true).'</pre>');
    //exit;
}
exit;
print('<pre>'.var_export($this->Controls, true).'</pre>');exit;
*/

				// replace control with control output
				$output = $template;
				foreach ($controls as $key=>$val)
				{
					$output = str_replace($controls[$key]['control'], $commands[$key], $output);
				}
//print('<pre>'.var_export($this->User, true).'</pre>');exit;
//print('<pre>'.var_export($_SESSION['user'], true).'</pre>');exit;

				
				$scripts = '';
				if (isset($this->User)) // && $this->User->EditMode
				{
					$scripts .= '<script language="javascript" type="text/javascript" src="/WebCMS/assets/WebCMS.js"></script>'."\n";
					//$scripts .= '<script language="javascript" type="text/javascript" src="/WebCMS/assets/mootools.js"></script>'."\n";
				}
				$output = str_replace('<!-- WebCMS SCRIPTS -->', $scripts, $output);

				// write to cache
				if ($staticPage)
				{
					if (!$handle = fopen($fileCache, 'w'))
					{
						$this->Error500('Cannot open file for writing');
					}
				}
				else
				{
					$dynamicFile = $dynamicPage;
					if (!$handle = fopen($dynamicPage, 'w'))
					{
						$this->Error500('Cannot open file for writing');
					}
				}

				if (fwrite($handle, $output) === FALSE) {
					$this->Error500('Cannot write to file');
				}

				fclose($handle);
				
				// update db
				$this->cacheCreated = mktime();
				$this->Persist();
				
				$retval = true;
			}
			else
			{
				$this->Error404('Invalid page request. (Page)');
			}
		}
		else
		{
			$this->Error404('Template file does not exist. (Page)');
		}
		
		return $retval;
	}
	
	function IsValid()
	{
		$isValid = true;

// TODO: fix this		
//		$isValid = $isValid && count($this->args) == $this->pageConfig['argCount'];
		
		return $isValid;
	}

	function TimeAdd($timestamp, $seconds=0, $minutes=0, $hours=0, $days=0, $months=0, $years=0)
	{
	   $timePieces = getdate($timestamp);
	   
	   return mktime($timePieces["hours"] + $hours,
	                   $timePieces["minutes"] + $minutes,
	                   $timePieces["seconds"] + $seconds,
	                   $timePieces["mon"] + $months,
	                   $timePieces["mday"] + $days,
	                   $timePieces["year"] + $years );
	}
	
	function Error404($message=null)
	{
		ob_clean();
		header("HTTP/1.0 404 Not Found");
		$error = new ErrorDocument(404, $message);
		ob_flush();
		exit;
	}

	function Error500($message=null)
	{
		ob_clean();
		header("HTTP/1.0 500 Internal Server Error.");
		$error = new ErrorDocument(500, $message);
		if ($message)
		{
			print('<br />Error: ' . $message);
		}
		ob_flush();
		exit;
	}
}
?>